/*
 Copyright (c) 2011, Intel Corporation. All rights reserved.

 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of Intel Corporation nor the names of its contributors may
   be used to endorse or promote products derived from this software without
   specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 ********************************************************************************
 *   Content : Eigen bindings to BLAS F77
 *   Triangular matrix * matrix product functionality based on ?TRMM.
 ********************************************************************************
*/

#ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_BLAS_H
#define EIGEN_TRIANGULAR_MATRIX_MATRIX_BLAS_H

namespace Eigen {

namespace internal {

template<typename Scalar,
		 typename Index,
		 int Mode,
		 bool LhsIsTriangular,
		 int LhsStorageOrder,
		 bool ConjugateLhs,
		 int RhsStorageOrder,
		 bool ConjugateRhs,
		 int ResStorageOrder>
struct product_triangular_matrix_matrix_trmm
	: product_triangular_matrix_matrix<Scalar,
									   Index,
									   Mode,
									   LhsIsTriangular,
									   LhsStorageOrder,
									   ConjugateLhs,
									   RhsStorageOrder,
									   ConjugateRhs,
									   ResStorageOrder,
									   1,
									   BuiltIn>
{};

// try to go to BLAS specialization
#define EIGEN_BLAS_TRMM_SPECIALIZE(Scalar, LhsIsTriangular)                                                            \
	template<typename Index, int Mode, int LhsStorageOrder, bool ConjugateLhs, int RhsStorageOrder, bool ConjugateRhs> \
	struct product_triangular_matrix_matrix<Scalar,                                                                    \
											Index,                                                                     \
											Mode,                                                                      \
											LhsIsTriangular,                                                           \
											LhsStorageOrder,                                                           \
											ConjugateLhs,                                                              \
											RhsStorageOrder,                                                           \
											ConjugateRhs,                                                              \
											ColMajor,                                                                  \
											1,                                                                         \
											Specialized>                                                               \
	{                                                                                                                  \
		static inline void run(Index _rows,                                                                            \
							   Index _cols,                                                                            \
							   Index _depth,                                                                           \
							   const Scalar* _lhs,                                                                     \
							   Index lhsStride,                                                                        \
							   const Scalar* _rhs,                                                                     \
							   Index rhsStride,                                                                        \
							   Scalar* res,                                                                            \
							   Index resIncr,                                                                          \
							   Index resStride,                                                                        \
							   Scalar alpha,                                                                           \
							   level3_blocking<Scalar, Scalar>& blocking)                                              \
		{                                                                                                              \
			EIGEN_ONLY_USED_FOR_DEBUG(resIncr);                                                                        \
			eigen_assert(resIncr == 1);                                                                                \
			product_triangular_matrix_matrix_trmm<Scalar,                                                              \
												  Index,                                                               \
												  Mode,                                                                \
												  LhsIsTriangular,                                                     \
												  LhsStorageOrder,                                                     \
												  ConjugateLhs,                                                        \
												  RhsStorageOrder,                                                     \
												  ConjugateRhs,                                                        \
												  ColMajor>::run(_rows,                                                \
																 _cols,                                                \
																 _depth,                                               \
																 _lhs,                                                 \
																 lhsStride,                                            \
																 _rhs,                                                 \
																 rhsStride,                                            \
																 res,                                                  \
																 resStride,                                            \
																 alpha,                                                \
																 blocking);                                            \
		}                                                                                                              \
	};

EIGEN_BLAS_TRMM_SPECIALIZE(double, true)
EIGEN_BLAS_TRMM_SPECIALIZE(double, false)
EIGEN_BLAS_TRMM_SPECIALIZE(dcomplex, true)
EIGEN_BLAS_TRMM_SPECIALIZE(dcomplex, false)
EIGEN_BLAS_TRMM_SPECIALIZE(float, true)
EIGEN_BLAS_TRMM_SPECIALIZE(float, false)
EIGEN_BLAS_TRMM_SPECIALIZE(scomplex, true)
EIGEN_BLAS_TRMM_SPECIALIZE(scomplex, false)

// implements col-major += alpha * op(triangular) * op(general)
#define EIGEN_BLAS_TRMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC)                                                      \
	template<typename Index, int Mode, int LhsStorageOrder, bool ConjugateLhs, int RhsStorageOrder, bool ConjugateRhs> \
	struct product_triangular_matrix_matrix_trmm<EIGTYPE,                                                              \
												 Index,                                                                \
												 Mode,                                                                 \
												 true,                                                                 \
												 LhsStorageOrder,                                                      \
												 ConjugateLhs,                                                         \
												 RhsStorageOrder,                                                      \
												 ConjugateRhs,                                                         \
												 ColMajor>                                                             \
	{                                                                                                                  \
		enum                                                                                                           \
		{                                                                                                              \
			IsLower = (Mode & Lower) == Lower,                                                                         \
			SetDiag = (Mode & (ZeroDiag | UnitDiag)) ? 0 : 1,                                                          \
			IsUnitDiag = (Mode & UnitDiag) ? 1 : 0,                                                                    \
			IsZeroDiag = (Mode & ZeroDiag) ? 1 : 0,                                                                    \
			LowUp = IsLower ? Lower : Upper,                                                                           \
			conjA = ((LhsStorageOrder == ColMajor) && ConjugateLhs) ? 1 : 0                                            \
		};                                                                                                             \
                                                                                                                       \
		static void run(Index _rows,                                                                                   \
						Index _cols,                                                                                   \
						Index _depth,                                                                                  \
						const EIGTYPE* _lhs,                                                                           \
						Index lhsStride,                                                                               \
						const EIGTYPE* _rhs,                                                                           \
						Index rhsStride,                                                                               \
						EIGTYPE* res,                                                                                  \
						Index resStride,                                                                               \
						EIGTYPE alpha,                                                                                 \
						level3_blocking<EIGTYPE, EIGTYPE>& blocking)                                                   \
		{                                                                                                              \
			Index diagSize = (std::min)(_rows, _depth);                                                                \
			Index rows = IsLower ? _rows : diagSize;                                                                   \
			Index depth = IsLower ? diagSize : _depth;                                                                 \
			Index cols = _cols;                                                                                        \
                                                                                                                       \
			typedef Matrix<EIGTYPE, Dynamic, Dynamic, LhsStorageOrder> MatrixLhs;                                      \
			typedef Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder> MatrixRhs;                                      \
                                                                                                                       \
			/* Non-square case - doesn't fit to BLAS ?TRMM. Fall to default triangular product or call BLAS ?GEMM*/    \
			if (rows != depth) {                                                                                       \
                                                                                                                       \
				/* FIXME handle mkl_domain_get_max_threads */                                                          \
				/*int nthr = mkl_domain_get_max_threads(EIGEN_BLAS_DOMAIN_BLAS);*/ int nthr = 1;                       \
                                                                                                                       \
				if (((nthr == 1) && (((std::max)(rows, depth) - diagSize) / (double)diagSize < 0.5))) {                \
					/* Most likely no benefit to call TRMM or GEMM from BLAS */                                        \
					product_triangular_matrix_matrix<EIGTYPE,                                                          \
													 Index,                                                            \
													 Mode,                                                             \
													 true,                                                             \
													 LhsStorageOrder,                                                  \
													 ConjugateLhs,                                                     \
													 RhsStorageOrder,                                                  \
													 ConjugateRhs,                                                     \
													 ColMajor,                                                         \
													 1,                                                                \
													 BuiltIn>::run(_rows,                                              \
																   _cols,                                              \
																   _depth,                                             \
																   _lhs,                                               \
																   lhsStride,                                          \
																   _rhs,                                               \
																   rhsStride,                                          \
																   res,                                                \
																   1,                                                  \
																   resStride,                                          \
																   alpha,                                              \
																   blocking);                                          \
					/*std::cout << "TRMM_L: A is not square! Go to Eigen TRMM implementation!\n";*/                    \
				} else {                                                                                               \
					/* Make sense to call GEMM */                                                                      \
					Map<const MatrixLhs, 0, OuterStride<>> lhsMap(_lhs, rows, depth, OuterStride<>(lhsStride));        \
					MatrixLhs aa_tmp = lhsMap.template triangularView<Mode>();                                         \
					BlasIndex aStride = convert_index<BlasIndex>(aa_tmp.outerStride());                                \
					gemm_blocking_space<ColMajor, EIGTYPE, EIGTYPE, Dynamic, Dynamic, Dynamic> gemm_blocking(          \
						_rows, _cols, _depth, 1, true);                                                                \
					general_matrix_matrix_product<Index,                                                               \
												  EIGTYPE,                                                             \
												  LhsStorageOrder,                                                     \
												  ConjugateLhs,                                                        \
												  EIGTYPE,                                                             \
												  RhsStorageOrder,                                                     \
												  ConjugateRhs,                                                        \
												  ColMajor,                                                            \
												  1>::run(rows,                                                        \
														  cols,                                                        \
														  depth,                                                       \
														  aa_tmp.data(),                                               \
														  aStride,                                                     \
														  _rhs,                                                        \
														  rhsStride,                                                   \
														  res,                                                         \
														  1,                                                           \
														  resStride,                                                   \
														  alpha,                                                       \
														  gemm_blocking,                                               \
														  0);                                                          \
                                                                                                                       \
					/*std::cout << "TRMM_L: A is not square! Go to BLAS GEMM implementation! " << nthr<<" \n";*/       \
				}                                                                                                      \
				return;                                                                                                \
			}                                                                                                          \
			char side = 'L', transa, uplo, diag = 'N';                                                                 \
			EIGTYPE* b;                                                                                                \
			const EIGTYPE* a;                                                                                          \
			BlasIndex m, n, lda, ldb;                                                                                  \
                                                                                                                       \
			/* Set m, n */                                                                                             \
			m = convert_index<BlasIndex>(diagSize);                                                                    \
			n = convert_index<BlasIndex>(cols);                                                                        \
                                                                                                                       \
			/* Set trans */                                                                                            \
			transa = (LhsStorageOrder == RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N';                               \
                                                                                                                       \
			/* Set b, ldb */                                                                                           \
			Map<const MatrixRhs, 0, OuterStride<>> rhs(_rhs, depth, cols, OuterStride<>(rhsStride));                   \
			MatrixX##EIGPREFIX b_tmp;                                                                                  \
                                                                                                                       \
			if (ConjugateRhs)                                                                                          \
				b_tmp = rhs.conjugate();                                                                               \
			else                                                                                                       \
				b_tmp = rhs;                                                                                           \
			b = b_tmp.data();                                                                                          \
			ldb = convert_index<BlasIndex>(b_tmp.outerStride());                                                       \
                                                                                                                       \
			/* Set uplo */                                                                                             \
			uplo = IsLower ? 'L' : 'U';                                                                                \
			if (LhsStorageOrder == RowMajor)                                                                           \
				uplo = (uplo == 'L') ? 'U' : 'L';                                                                      \
			/* Set a, lda */                                                                                           \
			Map<const MatrixLhs, 0, OuterStride<>> lhs(_lhs, rows, depth, OuterStride<>(lhsStride));                   \
			MatrixLhs a_tmp;                                                                                           \
                                                                                                                       \
			if ((conjA != 0) || (SetDiag == 0)) {                                                                      \
				if (conjA)                                                                                             \
					a_tmp = lhs.conjugate();                                                                           \
				else                                                                                                   \
					a_tmp = lhs;                                                                                       \
				if (IsZeroDiag)                                                                                        \
					a_tmp.diagonal().setZero();                                                                        \
				else if (IsUnitDiag)                                                                                   \
					a_tmp.diagonal().setOnes();                                                                        \
				a = a_tmp.data();                                                                                      \
				lda = convert_index<BlasIndex>(a_tmp.outerStride());                                                   \
			} else {                                                                                                   \
				a = _lhs;                                                                                              \
				lda = convert_index<BlasIndex>(lhsStride);                                                             \
			}                                                                                                          \
			/*std::cout << "TRMM_L: A is square! Go to BLAS TRMM implementation! \n";*/                                \
			/* call ?trmm*/                                                                                            \
			BLASFUNC(&side,                                                                                            \
					 &uplo,                                                                                            \
					 &transa,                                                                                          \
					 &diag,                                                                                            \
					 &m,                                                                                               \
					 &n,                                                                                               \
					 (const BLASTYPE*)&numext::real_ref(alpha),                                                        \
					 (const BLASTYPE*)a,                                                                               \
					 &lda,                                                                                             \
					 (BLASTYPE*)b,                                                                                     \
					 &ldb);                                                                                            \
                                                                                                                       \
			/* Add op(a_triangular)*b into res*/                                                                       \
			Map<MatrixX##EIGPREFIX, 0, OuterStride<>> res_tmp(res, rows, cols, OuterStride<>(resStride));              \
			res_tmp = res_tmp + b_tmp;                                                                                 \
		}                                                                                                              \
	};

#ifdef EIGEN_USE_MKL
EIGEN_BLAS_TRMM_L(double, double, d, dtrmm)
EIGEN_BLAS_TRMM_L(dcomplex, MKL_Complex16, cd, ztrmm)
EIGEN_BLAS_TRMM_L(float, float, f, strmm)
EIGEN_BLAS_TRMM_L(scomplex, MKL_Complex8, cf, ctrmm)
#else
EIGEN_BLAS_TRMM_L(double, double, d, dtrmm_)
EIGEN_BLAS_TRMM_L(dcomplex, double, cd, ztrmm_)
EIGEN_BLAS_TRMM_L(float, float, f, strmm_)
EIGEN_BLAS_TRMM_L(scomplex, float, cf, ctrmm_)
#endif

// implements col-major += alpha * op(general) * op(triangular)
#define EIGEN_BLAS_TRMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC)                                                      \
	template<typename Index, int Mode, int LhsStorageOrder, bool ConjugateLhs, int RhsStorageOrder, bool ConjugateRhs> \
	struct product_triangular_matrix_matrix_trmm<EIGTYPE,                                                              \
												 Index,                                                                \
												 Mode,                                                                 \
												 false,                                                                \
												 LhsStorageOrder,                                                      \
												 ConjugateLhs,                                                         \
												 RhsStorageOrder,                                                      \
												 ConjugateRhs,                                                         \
												 ColMajor>                                                             \
	{                                                                                                                  \
		enum                                                                                                           \
		{                                                                                                              \
			IsLower = (Mode & Lower) == Lower,                                                                         \
			SetDiag = (Mode & (ZeroDiag | UnitDiag)) ? 0 : 1,                                                          \
			IsUnitDiag = (Mode & UnitDiag) ? 1 : 0,                                                                    \
			IsZeroDiag = (Mode & ZeroDiag) ? 1 : 0,                                                                    \
			LowUp = IsLower ? Lower : Upper,                                                                           \
			conjA = ((RhsStorageOrder == ColMajor) && ConjugateRhs) ? 1 : 0                                            \
		};                                                                                                             \
                                                                                                                       \
		static void run(Index _rows,                                                                                   \
						Index _cols,                                                                                   \
						Index _depth,                                                                                  \
						const EIGTYPE* _lhs,                                                                           \
						Index lhsStride,                                                                               \
						const EIGTYPE* _rhs,                                                                           \
						Index rhsStride,                                                                               \
						EIGTYPE* res,                                                                                  \
						Index resStride,                                                                               \
						EIGTYPE alpha,                                                                                 \
						level3_blocking<EIGTYPE, EIGTYPE>& blocking)                                                   \
		{                                                                                                              \
			Index diagSize = (std::min)(_cols, _depth);                                                                \
			Index rows = _rows;                                                                                        \
			Index depth = IsLower ? _depth : diagSize;                                                                 \
			Index cols = IsLower ? diagSize : _cols;                                                                   \
                                                                                                                       \
			typedef Matrix<EIGTYPE, Dynamic, Dynamic, LhsStorageOrder> MatrixLhs;                                      \
			typedef Matrix<EIGTYPE, Dynamic, Dynamic, RhsStorageOrder> MatrixRhs;                                      \
                                                                                                                       \
			/* Non-square case - doesn't fit to BLAS ?TRMM. Fall to default triangular product or call BLAS ?GEMM*/    \
			if (cols != depth) {                                                                                       \
                                                                                                                       \
				int nthr = 1 /*mkl_domain_get_max_threads(EIGEN_BLAS_DOMAIN_BLAS)*/;                                   \
                                                                                                                       \
				if ((nthr == 1) && (((std::max)(cols, depth) - diagSize) / (double)diagSize < 0.5)) {                  \
					/* Most likely no benefit to call TRMM or GEMM from BLAS*/                                         \
					product_triangular_matrix_matrix<EIGTYPE,                                                          \
													 Index,                                                            \
													 Mode,                                                             \
													 false,                                                            \
													 LhsStorageOrder,                                                  \
													 ConjugateLhs,                                                     \
													 RhsStorageOrder,                                                  \
													 ConjugateRhs,                                                     \
													 ColMajor,                                                         \
													 1,                                                                \
													 BuiltIn>::run(_rows,                                              \
																   _cols,                                              \
																   _depth,                                             \
																   _lhs,                                               \
																   lhsStride,                                          \
																   _rhs,                                               \
																   rhsStride,                                          \
																   res,                                                \
																   1,                                                  \
																   resStride,                                          \
																   alpha,                                              \
																   blocking);                                          \
					/*std::cout << "TRMM_R: A is not square! Go to Eigen TRMM implementation!\n";*/                    \
				} else {                                                                                               \
					/* Make sense to call GEMM */                                                                      \
					Map<const MatrixRhs, 0, OuterStride<>> rhsMap(_rhs, depth, cols, OuterStride<>(rhsStride));        \
					MatrixRhs aa_tmp = rhsMap.template triangularView<Mode>();                                         \
					BlasIndex aStride = convert_index<BlasIndex>(aa_tmp.outerStride());                                \
					gemm_blocking_space<ColMajor, EIGTYPE, EIGTYPE, Dynamic, Dynamic, Dynamic> gemm_blocking(          \
						_rows, _cols, _depth, 1, true);                                                                \
					general_matrix_matrix_product<Index,                                                               \
												  EIGTYPE,                                                             \
												  LhsStorageOrder,                                                     \
												  ConjugateLhs,                                                        \
												  EIGTYPE,                                                             \
												  RhsStorageOrder,                                                     \
												  ConjugateRhs,                                                        \
												  ColMajor,                                                            \
												  1>::run(rows,                                                        \
														  cols,                                                        \
														  depth,                                                       \
														  _lhs,                                                        \
														  lhsStride,                                                   \
														  aa_tmp.data(),                                               \
														  aStride,                                                     \
														  res,                                                         \
														  1,                                                           \
														  resStride,                                                   \
														  alpha,                                                       \
														  gemm_blocking,                                               \
														  0);                                                          \
                                                                                                                       \
					/*std::cout << "TRMM_R: A is not square! Go to BLAS GEMM implementation! " << nthr<<" \n";*/       \
				}                                                                                                      \
				return;                                                                                                \
			}                                                                                                          \
			char side = 'R', transa, uplo, diag = 'N';                                                                 \
			EIGTYPE* b;                                                                                                \
			const EIGTYPE* a;                                                                                          \
			BlasIndex m, n, lda, ldb;                                                                                  \
                                                                                                                       \
			/* Set m, n */                                                                                             \
			m = convert_index<BlasIndex>(rows);                                                                        \
			n = convert_index<BlasIndex>(diagSize);                                                                    \
                                                                                                                       \
			/* Set trans */                                                                                            \
			transa = (RhsStorageOrder == RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N';                               \
                                                                                                                       \
			/* Set b, ldb */                                                                                           \
			Map<const MatrixLhs, 0, OuterStride<>> lhs(_lhs, rows, depth, OuterStride<>(lhsStride));                   \
			MatrixX##EIGPREFIX b_tmp;                                                                                  \
                                                                                                                       \
			if (ConjugateLhs)                                                                                          \
				b_tmp = lhs.conjugate();                                                                               \
			else                                                                                                       \
				b_tmp = lhs;                                                                                           \
			b = b_tmp.data();                                                                                          \
			ldb = convert_index<BlasIndex>(b_tmp.outerStride());                                                       \
                                                                                                                       \
			/* Set uplo */                                                                                             \
			uplo = IsLower ? 'L' : 'U';                                                                                \
			if (RhsStorageOrder == RowMajor)                                                                           \
				uplo = (uplo == 'L') ? 'U' : 'L';                                                                      \
			/* Set a, lda */                                                                                           \
			Map<const MatrixRhs, 0, OuterStride<>> rhs(_rhs, depth, cols, OuterStride<>(rhsStride));                   \
			MatrixRhs a_tmp;                                                                                           \
                                                                                                                       \
			if ((conjA != 0) || (SetDiag == 0)) {                                                                      \
				if (conjA)                                                                                             \
					a_tmp = rhs.conjugate();                                                                           \
				else                                                                                                   \
					a_tmp = rhs;                                                                                       \
				if (IsZeroDiag)                                                                                        \
					a_tmp.diagonal().setZero();                                                                        \
				else if (IsUnitDiag)                                                                                   \
					a_tmp.diagonal().setOnes();                                                                        \
				a = a_tmp.data();                                                                                      \
				lda = convert_index<BlasIndex>(a_tmp.outerStride());                                                   \
			} else {                                                                                                   \
				a = _rhs;                                                                                              \
				lda = convert_index<BlasIndex>(rhsStride);                                                             \
			}                                                                                                          \
			/*std::cout << "TRMM_R: A is square! Go to BLAS TRMM implementation! \n";*/                                \
			/* call ?trmm*/                                                                                            \
			BLASFUNC(&side,                                                                                            \
					 &uplo,                                                                                            \
					 &transa,                                                                                          \
					 &diag,                                                                                            \
					 &m,                                                                                               \
					 &n,                                                                                               \
					 (const BLASTYPE*)&numext::real_ref(alpha),                                                        \
					 (const BLASTYPE*)a,                                                                               \
					 &lda,                                                                                             \
					 (BLASTYPE*)b,                                                                                     \
					 &ldb);                                                                                            \
                                                                                                                       \
			/* Add op(a_triangular)*b into res*/                                                                       \
			Map<MatrixX##EIGPREFIX, 0, OuterStride<>> res_tmp(res, rows, cols, OuterStride<>(resStride));              \
			res_tmp = res_tmp + b_tmp;                                                                                 \
		}                                                                                                              \
	};

#ifdef EIGEN_USE_MKL
EIGEN_BLAS_TRMM_R(double, double, d, dtrmm)
EIGEN_BLAS_TRMM_R(dcomplex, MKL_Complex16, cd, ztrmm)
EIGEN_BLAS_TRMM_R(float, float, f, strmm)
EIGEN_BLAS_TRMM_R(scomplex, MKL_Complex8, cf, ctrmm)
#else
EIGEN_BLAS_TRMM_R(double, double, d, dtrmm_)
EIGEN_BLAS_TRMM_R(dcomplex, double, cd, ztrmm_)
EIGEN_BLAS_TRMM_R(float, float, f, strmm_)
EIGEN_BLAS_TRMM_R(scomplex, float, cf, ctrmm_)
#endif
} // end namespace internal

} // end namespace Eigen

#endif // EIGEN_TRIANGULAR_MATRIX_MATRIX_BLAS_H
